package com.java.springboot.elasticsearch.service;

import com.alibaba.fastjson.JSONObject;
import com.java.springboot.elasticsearch.param.BookSearchParam;
import com.java.springboot.elasticsearch.vo.BookSearchResultVO;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author zhangtengfei
 * @date 2021/10/11 17:19
 */

@Slf4j
@Service
public class ElasticSearchService {

    @Resource
    private RestHighLevelClient restHighLevelClient;

    public List<BookSearchResultVO> queryByRest(String indices, BookSearchParam param) {

        SearchRequest searchRequest = new SearchRequest(indices);
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(convertParam(param));
        if (param.getHighlightedField() != null) {
            // 高亮 就是加了 标签
            builder.highlighter(
                    new HighlightBuilder().field(param.getHighlightedField()).preTags("<h1 style='red'>").postTags("</h1>"));
        }
        log.info("对index: {} 检索, param: {}", indices, param.toString());
        builder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        searchRequest.source(builder);

        SearchResponse searchResponse;
        try {
            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            log.info("检索结果数: {}", searchResponse.getHits().getTotalHits());
            return convertResponse(searchResponse, param);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private BoolQueryBuilder convertParam(BookSearchParam param) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        /**
         * term 查询
         */
        if (StringUtils.hasText(param.getBookName())) {
            boolQueryBuilder.must(QueryBuilders.termQuery("name", param.getBookName()));
        }
        /**
         * range 查询
         */
        if (param.getPrice() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gt(param.getPrice()));
        }
        /**
         * query_string 查询
         */
        if (StringUtils.hasText(param.getDescription())) {
            boolQueryBuilder.must(QueryBuilders.queryStringQuery("description:" + param.getDescription()));
        }
        return boolQueryBuilder;
    }

    public List<BookSearchResultVO> convertResponse(SearchResponse response, BookSearchParam searchParam) {
        List<BookSearchResultVO> list = new ArrayList<>();
        if (response != null && response.getHits() != null) {
            String result = "";
            BookSearchResultVO e = new BookSearchResultVO();
            for (SearchHit hit : response.getHits()) {
                result = hit.getSourceAsString();
                Map<String, HighlightField> map = hit.getHighlightFields();
                if (StringUtils.hasText(result)) {
                    e = JSONObject.parseObject(result, BookSearchResultVO.class);
                }
                if (e != null) {
                    if (map != null) {
                        HighlightField field = map.get(searchParam.getHighlightedField());
                        if (field != null) {
                            String str = "";
                            for (Text text : field.fragments()) {
                                str += text.string();
                            }
                            Map<String, String> highlightMap = new HashMap<>();
                            highlightMap.put(field.getName(), str);
                            e.setDiscription(str);
                        }
                    }
                    list.add(e);
                }
            }
        }
        return list;
    }
}
